package com.nodusk.timeline.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.nodusk.timeline.common.Result;
import com.nodusk.timeline.entity.Blog;
import com.nodusk.timeline.service.BlogService;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author 今何许
 * @date 2021-08-14 19:34
 */
@RestController
public class SearchController {

    @Autowired
    private BlogService blogService;
    @Autowired
    private RestHighLevelClient client;

    /**
     * 添加Blogs
     *
     * @throws Exception
     */
    @GetMapping("/save")
    public String createDocument() throws Exception {
        BulkRequest request = new BulkRequest();
        request.timeout("10s");
        List<Blog> blogs = blogService.list();
        //批量请求，批量更新，删除都差不多！！！不设置id就会自动生成随机id，演示为批量插入
        for (Blog blog : blogs) {
            request.add(new IndexRequest("blogs")
                    .id(String.valueOf(blog.getId()))
                    .source(JSON.toJSONString(blog), XContentType.JSON));
        }
        BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
        return "更新是否失败：" + response.hasFailures();
    }

    @GetMapping("/search")
    public Result search(String keyword, @RequestParam(defaultValue = "1") Integer page) throws IOException {
        System.out.println("keyword:" + keyword);
        System.out.println("page:" + page);
        Map<String, Object> source = null;
        SearchRequest request = new SearchRequest("blogs");
        //创建查询条件
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.should(
                QueryBuilders.matchQuery("title", keyword)
        );
        boolQuery.should(
                QueryBuilders.matchQuery("content", keyword)
        );
        boolQuery.should(
                QueryBuilders.matchQuery("description", keyword)
        );

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 使用QueryBuilders工具，精确查询term
        sourceBuilder.from((page - 1) * 5);
        sourceBuilder.size(5);
        //配置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("description"); //绑定属性
        highlightBuilder.field("title"); //绑定属性
        highlightBuilder.field("content"); //绑定属性
        highlightBuilder.requireFieldMatch(false);
        highlightBuilder.preTags("<span style='color:red'>"); //设置前缀
        highlightBuilder.postTags("</span>"); //设置后缀
        sourceBuilder.highlighter(highlightBuilder);

        sourceBuilder.query(boolQuery);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        request.source(sourceBuilder);

        SearchResponse searchResponse = client.search(request, RequestOptions.DEFAULT);

        //获取查询结果

        List<Map<String, Object>> course = new ArrayList<>();
        if (searchResponse.status() != RestStatus.OK) {
            return Result.fail("操作失败");
        }
        long total = searchResponse.getHits().getTotalHits().value;
        System.out.println("hits:" + total);
        for (SearchHit hit : searchResponse.getHits()) {
            //获取高亮字段
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField title = highlightFields.get("title");
            HighlightField description = highlightFields.get("description");
            // HighlightField content = highlightFields.get("content");
            source = hit.getSourceAsMap();

            //千万记得要记得判断是不是为空,不然你匹配的第一个结果没有高亮内容,那么就会报空指针异常,这个错误一开始真的搞了很久
            if (title != null) {
                Text[] fragments = title.fragments();
                String name = "";
                for (Text text : fragments) {
                    name += text;
                }
                source.put("title", name);   //高亮字段替换掉原本的内容
            }
            if (description != null) {
                Text[] fragments = description.fragments();
                String name = "";
                for (Text text : fragments) {
                    name += text;
                }
                source.put("description", name);   //高亮字段替换掉原本的内容
            }
//            if (content != null) {
//                Text[] fragments = content.fragments();
//                String name = "";
//                for (Text text : fragments) {
//                    name += text;
//                }
//                source.put("content", name);   //高亮字段替换掉原本的内容
//            }
            course.add(source);

        }
        Map<String, Object> map = new HashMap<>();
        map.put("blogs", course);
        map.put("total", total);
        map.put("page", page);
        return Result.success(map);
    }

}
